﻿using Newtonsoft.Json.Linq;
using OpenTK.Compute.OpenCL;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ttbit.form.impl
{
    class PackItem : IPackItem
    {
        public string Name { get; set; }

        public string Type { get; set; }

        public bool IsText { get; set; }

        public bool IsGroup => false;

        public byte[] Bytes { get; set; }

        public string GetAsText()
        {
            return System.Text.Encoding.UTF8.GetString(Bytes, 0, Bytes.Length);
        }
    }
    enum PackItemType
    {
        Unknown,
        Text,
        Binary,
        PakFile,
        PakIndex,
        PakFolder,
    }

    internal class PackGroup_Folder : IPackGroup
    {

        public PackGroup_Folder(string name, string path)
        {
            this.Name = name;
            this.InternalResourcePath = path;
            GetAllResourceName();
        }
        string InternalResourcePath;

        PackItemType GetTypeByFilename(string filename)
        {
            if (filename == "ttpak.json")
                return PackItemType.PakIndex;
            var ext = Path.GetExtension(filename); ;
            switch (ext)
            {
                case ".ttimg":
                case ".ttfont":
                case ".bin":
                case ".bytes":
                case ".jpg"://jpg 和 png 也可以当作二进制资源打包
                case ".png":
                    return PackItemType.Binary;
                case ".txt":
                case ".json":
                case ".js":
                    return PackItemType.Text;
                case ".ttpak":
                    return PackItemType.PakFile;
                default:
                    return PackItemType.Unknown;
            }

        }
        //得到所有资源
        public string[] GetAllResourceName()
        {
     
        
            if (allfiles == null)
            {
                allfiles = new Dictionary<string, PackFileInfo>();

                //加载TagFile
                var rtagfile = System.IO.Path.Combine(InternalResourcePath, "ttpak.json");

                var txt = System.IO.File.ReadAllText(rtagfile);
                var json = JObject.Parse(txt);
                this.Type = json["type"].ToString();
                {
                    List<string> fileInc = new List<string>();
                    List<string> fileExu = new List<string>();

                    var include = json["include"] as JArray;
                    var exclude = json["exclude"] as JArray;

                    foreach (string inc in include)
                    {
                        var incfiles = System.IO.Directory.GetFiles(InternalResourcePath, inc, SearchOption.TopDirectoryOnly);
                        foreach(var f in incfiles)
                        {
                            fileInc.Add(f);
                        }
                    }
                    foreach (string exu in exclude)
                    {
                        var excfiles = System.IO.Directory.GetFiles(InternalResourcePath, exu, SearchOption.TopDirectoryOnly);
                        foreach (var f in excfiles)
                        {
                            fileExu.Add(f);
                        }
                    }
                    foreach (var file in fileInc)
                    {
                        if (fileExu.Contains(file))
                            continue;

                        var name = Path.GetFileNameWithoutExtension(file).ToLower();
                        if (allfiles.ContainsKey(name))
                        {
                            Console.Error.WriteLine("have same name.load file error:" + file);
                            continue;
                        }
                        //var path = Path.GetRelativePath(InternalResourcePath, file);
                        var type = GetTypeByFilename(System.IO.Path.GetFileName(file).ToLower());
                        if (type == PackItemType.Unknown)
                        {
                            continue;
                        }
                        if (type == PackItemType.PakIndex)
                        {
                            continue;

                        }
                        if (type == PackItemType.Binary || type == PackItemType.Text || type == PackItemType.PakFile)
                        {
                            allfiles[name] = new PackFileInfo() { type = type, path = file };
                        }

                    }
                }
                var paths = System.IO.Directory.GetDirectories(InternalResourcePath, "*", SearchOption.TopDirectoryOnly);
                foreach (var path in paths)
                {

                    var tagfile = System.IO.Path.Combine(path, "ttpak.json");
                    if (System.IO.File.Exists(tagfile))
                    {
                        var name = Path.GetFileNameWithoutExtension(path).ToLower();
                        allfiles[name] = new PackFileInfo() { type = PackItemType.PakFolder, path = path };
                    }
                }
            }
            return allfiles.Keys.ToArray();
        }
        public class PackFileInfo
        {
            public PackItemType type;
            public string path;//文件名或者目录名
        }
        Dictionary<string, PackFileInfo> allfiles;
        Dictionary<string, IPackItem> allItems;

        public string Name
        {
            get;
            private set;
        }

        public string Type
        {
            get;
            private set;
        }

        public bool IsText => false;

        public byte[] Bytes => throw new NotImplementedException();

        public bool IsGroup => true;

        public string GetAsText()
        {
            throw new NotImplementedException();
        }

        public IPackItem GetPackItem(string name)
        {
            if (allfiles == null)
                GetAllResourceName();
            if (allItems == null)
                allItems = new Dictionary<string, IPackItem>();

            if (allItems.TryGetValue(name.ToLower(), out var value))
            {
                return value;
            }
            else if (allfiles.TryGetValue(name.ToLower(), out var info))
            {
                IPackItem item = null;
                if (info.type == PackItemType.PakFolder)
                {
                    item = new PackGroup_Folder(name.ToLower(), info.path);
                }
                else if (info.type == PackItemType.PakFile)
                {
                    var fs = System.IO.File.OpenRead(info.path);
                    item = new PackGroup_Stream(name.ToLower(), fs);
                }
                else if (info.type == PackItemType.Binary)
                {
                    PackItem itemb = new PackItem();
                    var ext = Path.GetExtension(info.path);
                    itemb.Bytes = System.IO.File.ReadAllBytes(info.path);
                    itemb.Name = name;
                    itemb.Type = ext;
                    itemb.IsText = false;
                    item = itemb;
                }
                else if (info.type == PackItemType.Text)
                {
                    PackItem itemb = new PackItem();
                    var ext = Path.GetExtension(info.path);
                    itemb.Bytes = System.IO.File.ReadAllBytes(info.path);
                    itemb.Name = name;
                    itemb.Type = ext;
                    itemb.IsText = true;
                    item = itemb;
                }
                allItems[name] = item;
                return item;
            }
            else
            {
                return null;
            }
        }


    }

    internal class PackGroup_Stream : IPackGroup
    {
        int startseek;
        public PackGroup_Stream(string name, System.IO.Stream stream)
        {
            this.Name = name;
            if (!stream.CanSeek)
                throw new Exception("need seek stream.");
            this.startseek = (int)stream.Position;
        }
        public string Name
        {
            get;
            private set;
        }

        public string Type
        {
            get;
            private set;
        }

        public bool IsText => false;

        public bool IsGroup => true;

        public byte[] Bytes => throw new NotImplementedException();

        public string[] GetAllResourceName()
        {
            throw new NotImplementedException();
        }

        public string GetAsText()
        {
            throw new NotImplementedException();
        }

        public IPackItem GetPackItem(string name)
        {
            throw new NotImplementedException();
        }
    }

}
